package org.cashbook.core.objects.transaction;

import java.util.ArrayList;
import java.util.Set;

import org.cashbook.IO.IOFactory;
import org.cashbook.IO.dataManager.IDataManager;
import org.cashbook.core.IDFactory;
import org.cashbook.utilities.UtilitiesFactory;


public abstract class AbstractTransactionOverview implements ITransactionOverview {
	protected String month;
	protected int year;
	protected TransactionList transactions = new TransactionList();
	protected IDataManager dataManager;
	protected int transactionOverviewID;
	protected boolean bufferUptodate = false;
	
	/**
	 * Default constructor
	 * @param transactionHandler TransactionHandler instance
	 * @param month Month of this TransactionOverview
	 * @param year Year of this TransactionOverview
	 */
	public AbstractTransactionOverview(String month, int year) {
		transactionOverviewID = IDFactory.getTransactionOverviewID();
		UtilitiesFactory.getLogger().fine("TransactionOverview created [Month " + month + "; Year " + year + "; ID " + transactionOverviewID + "]", this);
		this.month = month;
		this.year = year;
		UtilitiesFactory.getLogger().info("Getting DataManager [TransactionOverview ID " + transactionOverviewID + "]", this);
		dataManager = IOFactory.getDataManager();
		
		loadTransactions();
	}
	
	@Override
	public void addTransaction(ITransaction transaction) {
		transactions.add(transaction);
		UtilitiesFactory.getLogger().finest("Added new transaction", this);
		bufferUptodate = false;
	}

	@Override
	public ITransaction getTransaction(int transactionID) {
		ITransaction transaction = null;
		
		for(ITransaction transactionFor : transactions)
			if(transactionFor.getTransactionID() == transactionID) {
				transaction = transactionFor;
				break;
			}
		if(transaction == null)
			UtilitiesFactory.getLogger().warning("Transaction not found! [Transaction ID " + transactionID + "]", this);
		else
			UtilitiesFactory.getLogger().finest("Returning transaction [Transaction ID " + transactionID + "]", this);
		return transaction;
	}

	@Override
	public void deleteTransaction(int transactionID) {
		UtilitiesFactory.getLogger().severe("Not yet implemented", this);
	}
	
	private void loadTransactions() {
		UtilitiesFactory.getLogger().info("Loading transactions for month " + month + ", year " + year + " via DataManager [TransactionOverview ID " + transactionOverviewID + "]", this);
		transactions = dataManager.readTransactionsFromBuffer(month, year);
	}

	@Override
	public String getMonth() {
		UtilitiesFactory.getLogger().finest("Returning month [TransactionOverview ID " + transactionOverviewID + "]", this);
		return month;
	}

	@Override
	public int getYear() {
		UtilitiesFactory.getLogger().finest("Returning year [TransactionOverview ID " + transactionOverviewID + "]", this);
		return year;
	}

	@Override
	public ArrayList<ITransaction> getTransactions(String account) {
		UtilitiesFactory.getLogger().finest("Returning transactions [TransactionOverview ID " + transactionOverviewID + "]", this);
		return transactions;
	}

	@Override
	public double getOpeningBalance() {
		UtilitiesFactory.getLogger().info("Calculating Opening Balance via TransactionHandler [TransactionOverview ID " + transactionOverviewID  + "]", this);
		return 0;
	}

	@Override
	public double getClosingBalance() {
		UtilitiesFactory.getLogger().info("Calculating Closing Balance via TransactionHandler [TransactionOverview ID " + transactionOverviewID  + "]", this);
		return 0;
	}

	@Override
	public double getSumEarnings() {
		UtilitiesFactory.getLogger().info("Calculating sum of all earnings [TransactionOverview ID " + transactionOverviewID  + "]", this);
		float sumEarnings = 0;
		for(ITransaction transaction : transactions) 
			if(transaction instanceof TransactionRevenue)
				sumEarnings += transaction.getAmount();
		
		return sumEarnings;
	}

	@Override
	public double getSumExpenses() {
		UtilitiesFactory.getLogger().info("Calculating sum of all expenses [TransactionOverview ID " + transactionOverviewID  + "]", this);
		float sumExpenses = 0;
		for(ITransaction transaction : transactions) 
			if(transaction instanceof TransactionExpense)
				sumExpenses += transaction.getAmount();
		
		return sumExpenses;
	}

	@Override
	public double getDifference() {
		UtilitiesFactory.getLogger().info("Calculating difference of all earnings and expenses [TransactionOverview ID " + transactionOverviewID  + "]", this);
		return (getSumEarnings() - getSumExpenses());
	}

	@Override
	public double SumSelectedTransactions(Set<ITransaction> transactions) {
		UtilitiesFactory.getLogger().severe("Not yet implemented!", this);
		return 0;
	}

	@Override
	public double BalanceAt(Integer day) {
		UtilitiesFactory.getLogger().severe("Not yet implemented!", this);
		return 0;
	}

	@Override
	public int hashCode() {
		UtilitiesFactory.getLogger().finest("Calculating hash code [Transaction ID " + transactionOverviewID + "]", this);
		final int prime = 31;
		int result = 1;
		result = prime * result + ((month == null) ? 0 : month.hashCode());
		result = prime * result + year;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		UtilitiesFactory.getLogger().finest("Comparing instance [Transaction ID " + transactionOverviewID + "]", this);
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AbstractTransactionOverview other = (AbstractTransactionOverview) obj;
		if (!month.equals(other.month))
			return false;
		if (year != other.year)
			return false;
		return true;
	}

	@Override
	public boolean bufferUptodate() {
		if(bufferUptodate)
			UtilitiesFactory.getLogger().finest("Transactions buffer is uptodate [TransactionOverview " + month + " " + year + "]", this);
		else
			UtilitiesFactory.getLogger().warning("Transactions buffer is not uptodate [TransactionOverview " + month + " " + year + "]", this);
		return bufferUptodate;
	}

	@Override
	public void updateBuffer() {
		UtilitiesFactory.getLogger().info("Current transactions written into buffer [TransactionOverview " + month + " " + year + "]", this);
		dataManager.writeTransactionsToBuffer(transactions, month, year);
	}
}
